<?php

/*
	This file is part of Mandragon.

    Mandragon is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    Mandragon is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with Mandragon.  If not, see <http://www.gnu.org/licenses/>.
*/
	
require_once 'PHPUnit/Framework.php';
require_once 'autoload.php';

class TestAccessManager extends PHPUnit_Framework_TestCase {
	
	function test_check_access_in_list_empty_accesslist() { 

		$access = new AccessManager();

		$actual = $access->check_access_in_list("test", array());
		$this->assertFalse($actual);
	}

	function test_check_access_in_list_with_regexp_on_and_succeeds() {
		
		$access = new AccessManager();
		$accesslist = array(array('action' => "oh my a Test", 'allow' => true));
		$actual = $access->check_access_in_list("test", $accesslist, true);
		$this->assertTrue($actual);
	}

	function test_check_access_in_list_with_regexp_on_and_not_allowed() {
		
		$access = new AccessManager();

		$accesslist = array(array('action' => "oh my a Test", 'allow' => false));
		$actual = $access->check_access_in_list("test", $accesslist, true);
		$this->assertFalse($actual);
	}

	function test_check_access_in_list_with_regexp_on_and_fails() {
		
		$access = new AccessManager();

		$accesslist = array(array('action' => "Mary had a little lamb", 'allow' => true));
		$actual = $access->check_access_in_list("test", $accesslist, true);
		$this->assertFalse($actual);
	}

	function test_check_access_in_list_with_regexp_off_and_fails() {
		
		$access = new AccessManager();

		$accesslist = array(array('action' => "oh my a Test", 'allow' => true));
		$actual = $access->check_access_in_list("test", $accesslist, false);
		$this->assertFalse($actual);
	}

	function test_check_access_in_list_with_regexp_off_and_succeeds() {
		
		$access = new AccessManager();

		$accesslist = array(array('action' => "test", 'allow' => true));
		$actual = $access->check_access_in_list("test", $accesslist, false);
		$this->assertTrue($actual);
	}

	function test_check_access_in_list_with_regexp_off_and_succeeds_but_not_allowed() {
		
		$access = new AccessManager();

		$accesslist = array(array('action' => "test", 'allow' => false));
		$actual = $access->check_access_in_list("test", $accesslist, false);
		$this->assertFalse($actual);
	}

	function test_generate_accesslist_for_directory_for_user_with_no_dirs() {
		$expected_remote_address = 'remote_address';
		$expected_forwarded_for = 'forwarded_for';
		$expected_where = "ACCESS_RULE.action_id = ACCESS_ACTION.action_id AND \n" .
				"\tACCESS_RULE.dir_id IN (0) AND \n" .
				"\t(\n" .
				"\t\tACCESS_RULE.ipstring LIKE '$expected_remote_address - $expected_forwarded_for' OR \n" .
				"\t\tACCESS_RULE.guest > 0\n" .
				"\t)";
		$expected_order = 'rank ASC';
		$expected_select_query = 'select_query';
		$expected_select_result = 'select_result';
		$expected_num_rows = 1;

		$_SERVER["REMOTE_ADDR"] = $expected_remote_address;
		$_SERVER["HTTP_X_FORWARDED_FOR"] = $expected_forwarded_for;

		$access = new AccessManager();	

		$mock_db_access = $this->getMock('DbAccessor');
		$mock_db_access->expects($this->at(0))
				->method('db_query_select')
				->with(array(
								array('allow'),
								array('action')), 
						array("ACCESS_RULE", "ACCESS_ACTION"), 
						$expected_where,
						$expected_order)
				->will($this->returnValue($expected_select_query));
		$mock_db_access->expects($this->at(1))
				->method('db_do_query')
				->with($expected_select_query)
				->will($this->returnValue($expected_select_result));
		$mock_db_access->expects($this->at(2))
				->method('db_num_rows')
				->with($expected_select_result)
				->will($this->returnValue($expected_num_rows));
		$mock_db_access->expects($this->at(3))
				->method('db_fetch_array')
				->with($expected_select_result)
				->will($this->returnValue(null));
		$access->set_db_accessor($mock_db_access);

		$actual = $access->generate_accesslist_for_directory_for_user(null, null);
		$this->assertEquals(array(), $actual);
	}

	function test_generate_accesslist_for_directory_for_user_with_dirs() {
		$expected_dir_id1 = 13245;
		$expected_dir_id2 = 25894;

		$directory_tree = array(
				array('dir_id' => $expected_dir_id1),
				array('dir_id' => $expected_dir_id2));

		$expected_remote_address = 'remote_address';
		$expected_forwarded_for = 'forwarded_for';
		$expected_where = "ACCESS_RULE.action_id = ACCESS_ACTION.action_id AND \n" .
				"\tACCESS_RULE.dir_id IN ($expected_dir_id1,$expected_dir_id2,0) AND \n" .
				"\t(\n" .
				"\t\tACCESS_RULE.ipstring LIKE '$expected_remote_address - $expected_forwarded_for' OR \n" .
				"\t\tACCESS_RULE.guest > 0\n" .
				"\t)";
		$expected_order = 'rank ASC';
		$expected_select_query = 'select_query';
		$expected_select_result = 'select_result';
		$expected_num_rows = 1;

		$_SERVER["REMOTE_ADDR"] = $expected_remote_address;
		$_SERVER["HTTP_X_FORWARDED_FOR"] = $expected_forwarded_for;

		$access = new AccessManager();	

		$mock_db_access = $this->getMock('DbAccessor');
		$mock_db_access->expects($this->at(0))
				->method('db_query_select')
				->with(array(
								array('allow'),
								array('action')), 
						array("ACCESS_RULE", "ACCESS_ACTION"), 
						$expected_where,
						$expected_order)
				->will($this->returnValue($expected_select_query));
		$mock_db_access->expects($this->at(1))
				->method('db_do_query')
				->with($expected_select_query)
				->will($this->returnValue($expected_select_result));
		$mock_db_access->expects($this->at(2))
				->method('db_num_rows')
				->with($expected_select_result)
				->will($this->returnValue($expected_num_rows));
		$mock_db_access->expects($this->at(3))
				->method('db_fetch_array')
				->with($expected_select_result)
				->will($this->returnValue(null));
		$access->set_db_accessor($mock_db_access);

		$actual = $access->generate_accesslist_for_directory_for_user($directory_tree, null);
		$this->assertEquals(array(), $actual);
	}

	function test_generate_accesslist_for_directory_for_user_with_user_id() {
		$expected_user_id = 2598;
		$expected_group_id1 = 2598;
		$expected_group_id2 = 36984;

		$expected_user = array('user_id' => $expected_user_id,
				'user_groups' => array($expected_group_id1, $expected_group_id2));

		$expected_remote_address = 'remote_address';
		$expected_forwarded_for = 'forwarded_for';
		$expected_where = "ACCESS_RULE.action_id = ACCESS_ACTION.action_id AND \n" .
				"\tACCESS_RULE.dir_id IN (0) AND \n" .
				"\t(\n" . 
				"\t\tACCESS_RULE.user_id = $expected_user_id OR \n" .
				"\t\tACCESS_RULE.usergroup_id IN ($expected_group_id1,$expected_group_id2,-1) OR \n" .
				"\t\tACCESS_RULE.ipstring LIKE '$expected_remote_address - $expected_forwarded_for' OR \n" .
				"\t\tACCESS_RULE.guest > 0\n" .
				"\t)";
		$expected_order = 'rank ASC';
		$expected_select_query = 'select_query';
		$expected_select_result = 'select_result';
		$expected_num_rows = 1;

		$_SERVER["REMOTE_ADDR"] = $expected_remote_address;
		$_SERVER["HTTP_X_FORWARDED_FOR"] = $expected_forwarded_for;

		$access = new AccessManager();	

		$mock_db_access = $this->getMock('DbAccessor');
		$mock_db_access->expects($this->at(0))
				->method('db_query_select')
				->with(array(
								array('allow'),
								array('action')), 
						array("ACCESS_RULE", "ACCESS_ACTION"), 
						$expected_where,
						$expected_order)
				->will($this->returnValue($expected_select_query));
		$mock_db_access->expects($this->at(1))
				->method('db_do_query')
				->with($expected_select_query)
				->will($this->returnValue($expected_select_result));
		$mock_db_access->expects($this->at(2))
				->method('db_num_rows')
				->with($expected_select_result)
				->will($this->returnValue($expected_num_rows));
		$mock_db_access->expects($this->at(3))
				->method('db_fetch_array')
				->with($expected_select_result)
				->will($this->returnValue(null));
		$access->set_db_accessor($mock_db_access);

		$actual = $access->generate_accesslist_for_directory_for_user(null, $expected_user);
		$this->assertEquals(array(), $actual);
	}

	function test_generate_accesslist_for_directory_for_user_with_no_rights() {
		$expected_remote_address = 'remote_address';
		$expected_forwarded_for = 'forwarded_for';
		$expected_where = "ACCESS_RULE.action_id = ACCESS_ACTION.action_id AND \n" .
				"\tACCESS_RULE.dir_id IN (0) AND \n" .
				"\t(\n" .
				"\t\tACCESS_RULE.ipstring LIKE '$expected_remote_address - $expected_forwarded_for' OR \n" .
				"\t\tACCESS_RULE.guest > 0\n" .
				"\t)";
		$expected_order = 'rank ASC';
		$expected_select_query = 'select_query';
		$expected_select_result = 'select_result';
		$expected_num_rows = 0;

		$_SERVER["REMOTE_ADDR"] = $expected_remote_address;
		$_SERVER["HTTP_X_FORWARDED_FOR"] = $expected_forwarded_for;

		$access = new AccessManager();	

		$mock_db_access = $this->getMock('DbAccessor');
		$mock_db_access->expects($this->at(0))
				->method('db_query_select')
				->with(array(
								array('allow'),
								array('action')), 
						array("ACCESS_RULE", "ACCESS_ACTION"), 
						$expected_where,
						$expected_order)
				->will($this->returnValue($expected_select_query));
		$mock_db_access->expects($this->at(1))
				->method('db_do_query')
				->with($expected_select_query)
				->will($this->returnValue($expected_select_result));
		$mock_db_access->expects($this->at(2))
				->method('db_num_rows')
				->with($expected_select_result)
				->will($this->returnValue($expected_num_rows));
		$mock_db_access->expects($this->never())
				->method('db_fetch_array');
		$access->set_db_accessor($mock_db_access);

		$mock_error_nav = $this->getMock('ErrorNavigation');
		$mock_error_nav->expects($this->once())
				->method('errorpage')
				->with(3)
				->will($this->throwException(new RedirectException()));
		$access->set_error_navigation($mock_error_nav);

		try {
			$access->generate_accesslist_for_directory_for_user(null, null);
			$this->fail("mock object should've thrown RedirectException");
		} catch(RedirectException $ex) {
		}
	}

	function test_generate_accesslist_for_directory_for_user_with_rights() {
		$expected_dir_id1 = 13245;
		$expected_dir_id2 = 25894;

		$directory_tree = array(
				array('dir_id' => $expected_dir_id1),
				array('dir_id' => $expected_dir_id2));

		$expected_user_id = 2598;
		$expected_group_id1 = 2598;
		$expected_group_id2 = 36984;

		$expected_user = array('user_id' => $expected_user_id,
				'user_groups' => array($expected_group_id1, $expected_group_id2));

		$expected_remote_address = 'remote_address';
		$expected_forwarded_for = 'forwarded_for';
		$expected_where = "ACCESS_RULE.action_id = ACCESS_ACTION.action_id AND \n" .
				"\tACCESS_RULE.dir_id IN ($expected_dir_id1,$expected_dir_id2,0) AND \n" .
				"\t(\n" .
				"\t\tACCESS_RULE.ipstring LIKE '$expected_remote_address - $expected_forwarded_for' OR \n" .
				"\t\tACCESS_RULE.guest > 0\n" .
				"\t)";
		$expected_order = 'rank ASC';
		$expected_select_query = 'select_query';
		$expected_select_result = 'select_result';
		$expected_num_rows = 3;
		$expected_result_1 = 'result_1';
		$expected_result_2 = 'result_2'; 
		$expected_result_3 = 'result_3';

		$_SERVER["REMOTE_ADDR"] = $expected_remote_address;
		$_SERVER["HTTP_X_FORWARDED_FOR"] = $expected_forwarded_for;

		$access = new AccessManager();	

		$mock_db_access = $this->getMock('DbAccessor');
		$mock_db_access->expects($this->at(0))
				->method('db_query_select')
				->with(array(
								array('allow'),
								array('action')), 
						array("ACCESS_RULE", "ACCESS_ACTION"), 
						$expected_where,
						$expected_order)
				->will($this->returnValue($expected_select_query));
		$mock_db_access->expects($this->at(1))
				->method('db_do_query')
				->with($expected_select_query)
				->will($this->returnValue($expected_select_result));
		$mock_db_access->expects($this->at(2))
				->method('db_num_rows')
				->with($expected_select_result)
				->will($this->returnValue($expected_num_rows));
		$mock_db_access->expects($this->exactly(4))
				->method('db_fetch_array')
				->with($expected_select_result)
				->will($this->onConsecutiveCalls($expected_result_1, $expected_result_2, $expected_result_3, null));
		$access->set_db_accessor($mock_db_access);

		$mock_error_nav = $this->getMock('ErrorNavigation');
		$mock_error_nav->expects($this->never())
				->method('errorpage');
		$access->set_error_navigation($mock_error_nav);

		$actual = $access->generate_accesslist_for_directory_for_user($directory_tree, null);
		$this->assertEquals($expected_result_1, $actual[0]);
		$this->assertEquals($expected_result_2, $actual[1]);
		$this->assertEquals($expected_result_3, $actual[2]);
		$this->assertEquals(3, count($actual));
	}
}

class RedirectException extends Exception {
}

?>
